{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    ".. _nb_results:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Result"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "After an algorithm has been executed a result object is returned. In the following, single- and multi-objective runs with and without constraints are shown and the corresponding `Result` object is explained:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pymoo.algorithms.so_genetic_algorithm import GA\n",
    "from pymoo.factory import get_problem\n",
    "from pymoo.optimize import minimize\n",
    "\n",
    "\n",
    "problem = get_problem(\"sphere\")\n",
    "algorithm = GA(pop_size=5)\n",
    "res = minimize(problem,\n",
    "               algorithm,\n",
    "               ('n_gen', 30),\n",
    "               seed=1)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In this single-objective optimization problem, there exists a single best solution that was found. \n",
    "The result contains directly the best found values in the corresponding spaces. \n",
    "\n",
    "- `res.X` design space values are \n",
    "- `res.F` objective spaces values\n",
    "- `res.G` constraint values\n",
    "- `res.CV` aggregated constraint violation\n",
    "- `res.algorithm` algorithm object\n",
    "- `res.pop` final population object\n",
    "- `res.history` history of algorithm object. (only if `save_history` has been enabled during the algorithm initialization)\n",
    "- `res.time` the time required to run the algorithm\n",
    "\n",
    "Note, when the `minimize` function is called a deep copy of the algorithm object is created.\n",
    "This ensures that two independent runs with the same algorithm and same random seed have the same results without any side effects.\n",
    "\n",
    "The values from the final population can be extracted by using the `get` method. \n",
    "The population object is used internally, and store information for each individual. The `get`\n",
    "method allows to return vectors or matrices based on the provided properties.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([0.38401994, 0.51096839, 0.51958345, 0.50705362, 0.64625327,\n",
       "        0.52972181, 0.51346167, 0.57393803, 0.48975355, 0.49213286]),\n",
       " array([0.04209328]),\n",
       " None,\n",
       " array([0.]))"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "res.X, res.F, res.G, res.CV"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(<pymoo.algorithms.so_genetic_algorithm.GA at 0x122ea4050>,\n",
       " Population([<pymoo.model.individual.Individual object at 0x122ea91d0>,\n",
       "             <pymoo.model.individual.Individual object at 0x122ea95d0>,\n",
       "             <pymoo.model.individual.Individual object at 0x122ea9590>,\n",
       "             <pymoo.model.individual.Individual object at 0x122ea9210>,\n",
       "             <pymoo.model.individual.Individual object at 0x122ea9310>],\n",
       "            dtype=object))"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "res.algorithm, res.pop"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The values from the final population can be extracted by using the `get` method. \n",
    "The population object is used internally, and store information for each individual. The `get`\n",
    "method allows to return vectors or matrices based on the provided properties."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([[0.38401994, 0.51096839, 0.51958345, 0.50705362, 0.64625327,\n",
       "         0.52972181, 0.51346167, 0.57393803, 0.48975355, 0.49213286],\n",
       "        [0.38401994, 0.51096839, 0.51958345, 0.50705362, 0.64625327,\n",
       "         0.52972181, 0.51346167, 0.57393803, 0.51785226, 0.49213286],\n",
       "        [0.38401994, 0.51099826, 0.44223106, 0.50705362, 0.64625327,\n",
       "         0.52808581, 0.51346167, 0.57393803, 0.39462856, 0.49213286],\n",
       "        [0.38401994, 0.51099826, 0.44223106, 0.50705362, 0.64625327,\n",
       "         0.52864113, 0.51346167, 0.57393803, 0.39462856, 0.49213286],\n",
       "        [0.38401994, 0.47389685, 0.44223106, 0.50705362, 0.64625327,\n",
       "         0.52808581, 0.51346167, 0.57393803, 0.39462856, 0.49213286]]),\n",
       " array([[0.04209328],\n",
       "        [0.04230699],\n",
       "        [0.05595125],\n",
       "        [0.05598275],\n",
       "        [0.05651167]]))"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "res.pop.get(\"X\"), res.pop.get(\"F\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In this run, the problem did not have any constraints and therefore `res.G` evaluated to `None`.\n",
    "Also note, that `res.CV` will always be set to 0 no matter if the problem has constraints or not."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let us consider a problem that has, in fact, constraints:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "===========================================================================\n",
      "n_gen |  n_eval |   cv (min)   |   cv (avg)   |     fopt     |     favg    \n",
      "===========================================================================\n",
      "    1 |       5 |  1.35027E+02 |  5.47570E+02 |            - |            -\n",
      "    2 |      10 |  1.35027E+02 |  3.16525E+02 |            - |            -\n",
      "    3 |      15 |  1.35027E+02 |  2.16131E+02 |            - |            -\n",
      "    4 |      20 |  1.35027E+02 |  1.60240E+02 |            - |            -\n",
      "    5 |      25 |  1.33435E+02 |  1.38575E+02 |            - |            -\n"
     ]
    }
   ],
   "source": [
    "problem = get_problem(\"g01\")\n",
    "algorithm = GA(pop_size=5)\n",
    "res = minimize(problem,\n",
    "               algorithm,\n",
    "               ('n_gen', 5),\n",
    "               verbose=True,\n",
    "               seed=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(None, None, None, None)"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "res.X, res.F, res.G, res.CV"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here, the algorithm was not able to find any feasible solution in 5 generations. Therefore, all values contained in the results are equals to `None`. If in this case the least feasible solution should be returned, the flag `return_least_infeasible` needs to be enabled:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "===========================================================================\n",
      "n_gen |  n_eval |   cv (min)   |   cv (avg)   |     fopt     |     favg    \n",
      "===========================================================================\n",
      "    1 |       5 |  1.35027E+02 |  5.47570E+02 |            - |            -\n",
      "    2 |      10 |  1.35027E+02 |  3.16525E+02 |            - |            -\n",
      "    3 |      15 |  1.35027E+02 |  2.16131E+02 |            - |            -\n",
      "    4 |      20 |  1.35027E+02 |  1.60240E+02 |            - |            -\n",
      "    5 |      25 |  1.33435E+02 |  1.38575E+02 |            - |            -\n"
     ]
    }
   ],
   "source": [
    "problem = get_problem(\"g01\")\n",
    "algorithm = GA(pop_size=5, return_least_infeasible=True)\n",
    "res = minimize(problem,\n",
    "               algorithm,\n",
    "               ('n_gen', 5),\n",
    "               verbose=True,\n",
    "               seed=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(None, None, None, None)"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "res.X, res.F, res.G, res.CV"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We have made this design decision, because an infeasible solution can often not be considered as a solution\n",
    "of the optimization problem. Therefore, having a solution equals to `None` indicates the fact no feasible solution has been found."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If the problem has multiple objective, the result object has the same structure but `res.X`, `res.F`, `res.G`, `res.CV` are a set \n",
    "of non-dominated solutions instead of a single one."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pymoo.algorithms.nsga2 import NSGA2\n",
    "\n",
    "problem = get_problem(\"zdt2\")\n",
    "algorithm = NSGA2()\n",
    "res = minimize(problem,\n",
    "               algorithm,\n",
    "               ('n_gen', 10),\n",
    "               seed=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[4.02723032e-01, 2.92285190e+00],\n",
       "       [2.42936792e-03, 3.09049957e+00],\n",
       "       [6.42640810e-05, 3.80452248e+00],\n",
       "       [9.03843390e-02, 2.97779402e+00],\n",
       "       [7.51601609e-04, 3.12489259e+00],\n",
       "       [2.66638116e-05, 4.15122904e+00],\n",
       "       [5.32367109e-01, 2.91333135e+00],\n",
       "       [7.51074119e-05, 3.17766175e+00],\n",
       "       [9.96726161e-01, 2.73633323e+00],\n",
       "       [9.37668137e-01, 2.76323527e+00],\n",
       "       [2.78148785e-05, 3.90537318e+00]])"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "res.F"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
